package bjut.zrpc.core.optimization.handler;

import bjut.zrpc.core.optimization.bean.ZRpcServiceBean;
import bjut.zrpc.core.optimization.enums.ZRpcConfigEnum;
import bjut.zrpc.core.optimization.enums.ZRpcResponseEnum;
import bjut.zrpc.core.optimization.extension.ExtensionLoader;
import bjut.zrpc.core.optimization.interfaces.ServiceRegistry;
import bjut.zrpc.core.optimization.message.ZRpcRequestMessage;
import bjut.zrpc.core.optimization.message.ZRpcResponseMessage;
import bjut.zrpc.core.optimization.utils.PropertiesReadUtil;
import io.netty.channel.ChannelFutureListener;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @Author: zhuzhiming
 * @Date: 2022/6/24 12:12
 */
@Slf4j
public class ZRpcRequestHandler {

    private final ServiceRegistry serviceRegistry;

    public ZRpcRequestHandler() {
        String registry = PropertiesReadUtil.getConfig(ZRpcConfigEnum.ZRPC_REGISTRY.getPropertyValue()[0]);
        serviceRegistry = ExtensionLoader.getExtensionLoader(ServiceRegistry.class).getExtension(registry);
    }


    public Object handler(ZRpcRequestMessage zRpcRequestMessage, ZRpcServiceBean zRpcServiceBean, Semaphore semaphore) {

        if (semaphore != null) {
            try {
                boolean tryAcquire = semaphore.tryAcquire(1, zRpcServiceBean.getTimeout(), TimeUnit.MILLISECONDS);
                if (!tryAcquire) {
                    return null;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        String serviceInfo = zRpcRequestMessage.getServiceInfo();

        Object service;
        try {
            service = serviceRegistry.getService(serviceInfo);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return invokeTargetMethod(service, zRpcRequestMessage);

    }

    private Object invokeTargetMethod(Object service, ZRpcRequestMessage zRpcRequestMessage) {

        Object result;

        try {
            Method method = service.getClass().getMethod(zRpcRequestMessage.getMethodName(), zRpcRequestMessage.getParametersType());
            result = method.invoke(service, zRpcRequestMessage.getParameters());
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e.getMessage());
        }

        return result;

    }

}
